package com.hjk.shiny.androidcontrols;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.FrameLayout;

/**
 * Created by frank on 2017/6/20.
 */

public class DragViewGroup extends FrameLayout {
    private static final String TAG = "TestViewGroup";

    // 记录手指上次触摸的坐标
    private float mLastPointX;
    private float mLastPointY;

    // 记录被拖拽之前 child 的位置坐标   用作回弹记录的坐标点
    private float mDragViewOrigX;
    private float mDragViewOrigY;

    //用于识别最小的滑动距离,在构造中已初始化
    private int mSlop;
    // 用于标识正在被拖拽的 child，为 null 时表明没有 child 被拖拽
    private View mDragView;

    // 状态分别空闲、拖拽两种
    enum State {
        IDLE,
        DRAGGING
    }

    //当前event状态，对应enum State
    State mCurrentState;

    //layout构造
    public DragViewGroup(Context context) {
        this(context,null);
    }

    public DragViewGroup(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }


    public DragViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mSlop = ViewConfiguration.getWindowTouchSlop();
    }


    //关于event的事件传递监听
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return true;
    }

    //关于layout事件监听

    /**
     * 关于视图坐标系的计算环境
     *event.getX(),event.getY()获取关于触发事件点相对于父容器x,y的距离
     * ViewCompat类主要提供视图的兼容性，
     * 此处通过offsetLeftAndRight,offsetTopAndBottom对目标childview进行位移
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();

        switch (action){
            case MotionEvent.ACTION_DOWN:
                //仅记录触发childview 的事件位置
                if ( isPointOnViews(event)) {
                    //标记状态为拖拽，并记录上次触摸坐标
                    mCurrentState = State.DRAGGING;
                    mLastPointX = event.getX();
                    mLastPointY = event.getY();
                }
                break;

            case MotionEvent.ACTION_MOVE:
                //计算移动的差值
                int deltaX = (int) (event.getX() - mLastPointX);
                int deltaY = (int) (event.getY() - mLastPointY);
                if (mCurrentState == State.DRAGGING && mDragView != null
                        && (Math.abs(deltaX) > mSlop || Math.abs(deltaY) > mSlop)) {
                    //如果符合条件则对被拖拽的 child 进行位置移动
                    ViewCompat.offsetLeftAndRight(mDragView,deltaX);
                    ViewCompat.offsetTopAndBottom(mDragView,deltaY);
                    //记录当前点位置
                    mLastPointX = event.getX();
                    mLastPointY = event.getY();
                }
                break;

            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                if ( mCurrentState == State.DRAGGING ){
                    // 标记状态为空闲，并将 mDragView 变量置为 null
//                    mCurrentState = State.IDLE;
//                    mDragView = null;

                    //设置回弹
                    /**
                     * 回弹效果的实现
                     * 1.记录 child 原来位置的坐标。
                     * 2.手指释放时借助于属性动画，从新的位置到原始位置做数值变化，变化的过程中移动 child 最终就形成了回弹的动画效果。
                     */
                    if(mDragView!=null){
                        //创建回弹动画，确定动画起点与终点
                        ValueAnimator animator=ValueAnimator.ofFloat(mDragView.getX(),mDragViewOrigX);
                        //创建X动画监听
                        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                            @Override
                            public void onAnimationUpdate(ValueAnimator animation) {
                                mDragView.setX((float)animation.getAnimatedValue());
                            }
                        });

                        ValueAnimator animator1=ValueAnimator.ofFloat(mDragView.getY(),mDragViewOrigY);
                        //创建Y动画监听
                        animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                            @Override
                            public void onAnimationUpdate(ValueAnimator animation) {
                                mDragView.setY((float)animation.getAnimatedValue());
                            }
                        });

                        AnimatorSet animatorSet=new AnimatorSet();
                        animatorSet.play(animator).before(animator1);
                        //添加结束动画监听
                        animatorSet.addListener(new AnimatorListenerAdapter() {
                            @Override
                            public void onAnimationEnd(Animator animation) {
                                super.onAnimationEnd(animation);
                                mDragView=null;
                            }
                        });

                        animatorSet.start();

                    }else{
                        mDragView=null;
                    }

                    mCurrentState=State.IDLE;

                }
                break;
        }
        return true;
    }

    /**
     * 判断触摸的位置是否落在 child 身上
     *
     * */
//    private boolean isPointOnViews(MotionEvent ev) {
//        boolean result = false;
//        创建childView 矩阵
//        Rect rect = new Rect();
//        //event父布局所有childView,判断触发点是否在子view上
//        for (int i = 0;i < getChildCount();i++) {
//            View view = getChildAt(i);
//            /*
//              相对父布局而言，距left,top,right,bottom的距离
//             */
//            rect.set((int)view.getX(),(int)view.getY(),(int)view.getX()+(int)view.getWidth()
//                    ,(int)view.getY()+view.getHeight());
//
//            //判断包含关系
//            if (rect.contains((int)ev.getX(),(int)ev.getY())){
//                //标记被拖拽的child
//                mDragView = view;
//                result = true;
//                break;
//            }
//        }
//
//        在做mCurrentState判断前，mCurrentState还未被赋值为State.Dragging
//        return  result && mCurrentState != State.DRAGGING;
//    }




    /*
    由于 FrameLayout 的特性，最上面的 child 其实在 ViewGroup 的索引位置最靠后
    所以可以将遍历的顺序进行倒置，以符合视图的拖拽的顺序
    解决了拖拽的先后问题，但无法解决层叠问题，后渲染的view只能层叠在先渲染的view的上面
    这个与压栈的先后顺序有关
     */

    private boolean isPointOnViews(MotionEvent event){
        boolean result=false;
        Rect rect=new Rect();
        /*
        注意：反序检索时，应从getChildCount-1开始为最后一个child,当i=0时为第一个child,类似String.length的处理
         */
        for(int i=getChildCount()-1;i>=0;i--){
            View view=getChildAt(i);
            rect.set((int)view.getX(),(int)view.getY(),(int)view.getX()+(int)view.getWidth(),(int)view.getY()+(int)view.getHeight());
            if(rect.contains((int)event.getX(),(int)event.getY())){
                mDragView=view;
                // 保存拖拽之间 child 的位置坐标,以便回弹
                mDragViewOrigX = mDragView.getX();
                mDragViewOrigY = mDragView.getY();
                result=true;
                break;
            }
        }

        return result && mCurrentState!=State.DRAGGING;
    }


}